package com.suven.framework.core.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.InitializingBean;

import java.lang.reflect.Method;
import java.util.Objects;

public class CglibProxyFactory<T> implements MethodInterceptor, InitializingBean {
    private final Class<T> proxyInterfaceClass;
    private final ProxyMethodTarget proxyMethodTarget;
    private T proxyTarget;


    public CglibProxyFactory(Class<T> proxyInterfaceClass, ProxyMethodTarget proxyMethodTarget) {
        this.proxyInterfaceClass = proxyInterfaceClass;
        this.proxyMethodTarget = proxyMethodTarget;
    }

    public T getObject() {
        return proxyTarget;
    }

    public Class<?> getObjectType() {
        return proxyTarget.getClass();
    }

    public Object getMethodTarget(Method method){
        return proxyMethodTarget.getMethodTarget(method);
    }

    public  T createProxy() {
        Enhancer en = new Enhancer();
        //设置代理的父类
        en.setSuperclass(proxyInterfaceClass);
        //设置方法回调
        en.setCallback(this);
        //创建代理实例
        proxyTarget = (T)en.create();
        return proxyTarget;
    }

    @Override
    //参数中的object是目标对象，method和args是目标对象的方法和参数，methodProxy是方法代理
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result;
        Object target = this.getMethodTarget(method);
        if (Objects.nonNull(target)){
            result =  methodProxy.invoke(target, args);
            return result;
        }
        result = methodProxy.invokeSuper(object, args);
        return result;
    }


    /**
     * Invoked by the containing {@code BeanFactory} after it has set all bean properties
     * <p>This method allows the bean instance to perform validation of its overall
     * configuration and final initialization when all bean properties have been set.
     *
     * @throws Exception in the event of misconfiguration (such as failure to set an
     *                   essential property) or if initialization fails for any other reason
     */
    @Override
    public void afterPropertiesSet() {
        proxyTarget =  this.createProxy();
    }
}
